package com.weilele.mvvm

import android.app.Activity
import android.app.Application
import android.content.Intent
import android.os.Bundle
import android.os.Handler
import android.os.Looper
import android.util.Log
import androidx.lifecycle.ProcessLifecycleOwner
import com.github.jokar.multilanguages.library.MultiLanguage
import com.google.gson.Gson
import com.orhanobut.logger.AndroidLogAdapter
import com.orhanobut.logger.Logger
import com.orhanobut.logger.PrettyFormatStrategy
import com.tencent.mmkv.MMKV
import com.weilele.mvvm.base.MvvmActivity
import com.weilele.mvvm.sdk.UmengHelper
import com.weilele.mvvm.utils.`object`.ScreenAdaptationObj
import com.weilele.mvvm.utils.local.AppBackgroundRun
import com.weilele.mvvm.utils.local.LocalManageUtil
import com.weilele.mvvm.utils.net.OkHttpCertUtils
import okhttp3.FormBody
import okhttp3.Interceptor
import okhttp3.OkHttpClient
import okhttp3.Response
import okhttp3.internal.readBomAsCharset
import java.util.concurrent.TimeUnit
import kotlin.text.Charsets.UTF_8

//---------------------------------------------初始化mvvm库--------------------------------------
/**
 * gson
 */
val gson by lazy { Gson() }

/**
 * 主线程的handle
 */
val mainHandler by lazy { Handler(Looper.getMainLooper()) }

/**
 * 给外部调用创建okHttp设置参数的回调
 */
private var clientCall: ((OkHttpClient.Builder) -> Unit)? = null

/**
 * 当前app的包名
 */
val packageName by lazy { app.packageName }

/**
 * okHttp构建器
 */
val okHttpClientBuilder: OkHttpClient.Builder by lazy {
    OkHttpCertUtils.createCertOkHttpBuilder().apply {
        connectTimeout(3, TimeUnit.MINUTES)
        readTimeout(3, TimeUnit.MINUTES)
        writeTimeout(3, TimeUnit.MINUTES)
        if (MvvmConf.IS_DEBUG) {//debug模式
            //需要注意两种拦截器的区别
            addNetworkInterceptor {
                httpRequestLog(it)
            }
        }
    }
}

/**
 * okHttp对象
 */
val okHttpClient: OkHttpClient by lazy {
    clientCall?.invoke(okHttpClientBuilder)
    okHttpClientBuilder.build()
}

/**
 * 全局的application对象
 */
lateinit var app: Application

//启动的activity集合
val activityList = mutableListOf<Activity>()

/**
 * 设置创建全局OkHttpClient的监听
 */
fun setMvvmLibOnCreateOkHttpListener(call: ((OkHttpClient.Builder) -> Unit)) {
    clientCall = call
}

/**
 * [com.weilele.mvvm.MvvmConf]应该在此方法之前设置
 */
internal fun initMvvmLib(application: Application) {
    application.logI("---------------mvvm库初始化完毕-----------------------")
    app = application
    initMmkv()
    initLog()
    //初始化umeng（根据设置的uemng key来开关是否启动）
    UmengHelper.init()
    //语言国际化
    initLocal()
    //全局异常捕获会导致卡顿，待优化
//    Thread.setDefaultUncaughtExceptionHandler(CrashHelper)
    ProcessLifecycleOwner.get().lifecycle.addObserver(AppBackgroundRun)
    application.registerActivityLifecycleCallbacks(object : Application.ActivityLifecycleCallbacks {
        override fun onActivityPaused(activity: Activity) {
        }

        override fun onActivityStarted(activity: Activity) {
        }

        override fun onActivityDestroyed(activity: Activity) {
            activityList.remove(activity)
        }

        override fun onActivitySaveInstanceState(activity: Activity, outState: Bundle) {
        }

        override fun onActivityStopped(activity: Activity) {
        }

        override fun onActivityCreated(activity: Activity, savedInstanceState: Bundle?) {
            setScreenAdaptation(activity)
            activityList.add(activity)
        }

        override fun onActivityResumed(activity: Activity) {
        }
    })
}

private fun initLocal() {
    MultiLanguage.init { context -> //返回自己本地保存选择的语言设置
        LocalManageUtil.getCurrentSelectLocale(context)
    }
}

//是否开启屏幕适配,支持所有activity，字体过大可以调整缩放因子
fun setScreenAdaptation(activity: Activity) {
    //是否开启第三方库的屏幕适配
    if (MvvmConf.IS_CAN_SCREEN_ADAPTATION
            && MvvmConf.IS_CAN_SCREEN_OTHER_LIBRARY_ADAPTATION
            && activity !is MvvmActivity
    ) {
        ScreenAdaptationObj.setCustomDensity(activity)
    }
}

/**
 * 设置SP存储的文件名
 */
private fun initMmkv() {
    val rootDir: String = MMKV.initialize(app)
    "MMKV--->".logI("mmkv root: $rootDir")
}

/**
 * 初始化日志
 */
private fun initLog() {
    //不是debug模式不初始化
    if (!MvvmConf.IS_DEBUG) {
        return
    }
    //日志打印
    val formatStrategy = PrettyFormatStrategy.newBuilder()
            .showThreadInfo(false)  // (Optional) Whether to show thread info or not. Default true
            .methodCount(0)         // (Optional) How many method line to show. Default 2
            .methodOffset(7)        // (Optional) Hides internal method calls up to offset. Default 5
//            .logStrategy(customLog) // (Optional) Changes the log strategy to print out. Default LogCat
            .tag("--->")   // (Optional) Global tag for every log. Default PRETTY_LOGGER
            .build()
    Logger.addLogAdapter(AndroidLogAdapter(formatStrategy))
}

/**
 * 打印Http请求日志
 */
private fun httpRequestLog(chain: Interceptor.Chain): Response {
    val request = chain.request()
    val bodyStr = StringBuilder()
    val requestParams = when (val body = request.body) {
        is FormBody -> {
            repeat(body.size) {
                bodyStr.append(body.encodedName(it))
                bodyStr.append(":")
                bodyStr.append(body.encodedValue(it))
                bodyStr.append(",")
            }
            bodyStr.toString()
        }
        else -> {
            bodyStr.append(body.toString())
            bodyStr.append("\n不是FormBody，不支持打印请求参数").toString()
        }
    }
    Logger.v("发送请求：${request.url}\n请求参数：${requestParams}\n请求头:\n${request.headers}")
    val t1 = System.nanoTime()
    val response = chain.proceed(request)
    val t2 = System.nanoTime()
    val source = response.body?.source()
    source?.request(java.lang.Long.MAX_VALUE)
    val buffer = source?.buffer?.clone() ?: return response
    val charset =
            buffer.readBomAsCharset(response.body?.contentType()?.charset(UTF_8) ?: UTF_8)
    val responseStr = buffer.inputStream().bufferedReader(charset).readText()
    if ((responseStr.startsWith('{') || responseStr.startsWith('['))
            && (responseStr.endsWith('}') || responseStr.endsWith(']'))
    ) {
        Logger.json(
                "{\'响应链接\':\'${response.request.url}\',\'响应时间\':\'${(t2 - t1) / 1e6} ms\'," +
                        "\'响应数据\':${responseStr}}"
        )
    } else {
        Logger.v(
                "{\'响应链接\':\'${response.request.url}\',\n\'响应时间\':\'${(t2 - t1) / 1e6} ms\',\n" +
                        "\'响应数据\':${responseStr}}"
        )
    }
    return response
}

fun Any.printBundle(intent: Intent?) {
    printBundle(intent?.extras)
}

fun Any.printBundle(bundle: Bundle?) {
    bundle ?: return
    logV("开始打印Intent")
    bundle.keySet().forEach {
        logV("key:${it} value:${bundle.get(it)}")
    }
    logV("结束打印Intent")
}

fun Any.logI(msg: String?) {
    if (MvvmConf.IS_DEBUG) {
        Logger.i(this::class.java.simpleName + "--->" + msg)
    }
}

fun Any.logE(msg: String?) {
    if (MvvmConf.IS_DEBUG) {
        Logger.e(this::class.java.simpleName + "--->" + msg)
    }
}

fun Any.logV(msg: String?) {
    if (MvvmConf.IS_DEBUG) {
        Logger.v(this::class.java.simpleName + "--->" + msg)
    }
}

fun Any.logD(msg: String?) {
    if (MvvmConf.IS_DEBUG) {
        Logger.d(this::class.java.simpleName + "--->" + msg)
    }
}

fun Any.logW(msg: String?) {
    if (MvvmConf.IS_DEBUG) {
        Logger.w(this::class.java.simpleName + "--->" + msg)
    }
}

fun String?.log(tag: String? = null, level: Int = Log.VERBOSE) {
    if (MvvmConf.IS_DEBUG) {
        this ?: return
        val realTag = tag ?: "mvvmLibrary-->"
        val message = this
        when (level) {
            Log.VERBOSE -> {
                Log.v(realTag, message)
            }
            Log.DEBUG -> {
                Log.d(realTag, message)
            }
            Log.INFO -> {
                Log.i(realTag, message)
            }
            Log.WARN -> {
                Log.w(realTag, message)
            }
            else -> {
                Log.wtf(realTag, message)
            }
        }
    }
}